# -*- coding: utf-8 -*-
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
# Odoo Connector
# QQ:978979209
# Author：'zengfajun'
# Date：2018-06-25
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&


from odoo import tools
from odoo import api, fields, models
from odoo.addons import decimal_precision as dp
from odoo.exceptions import ValidationError


class AccountChargeOff(models.Model):
    _name = "account.charge.off"

    _description = "Account Charge Off"
    _auto = False
    _rec_name = 'partner_id'
    _order = 'partner_id desc'

    partner_id = fields.Many2one('res.partner', u'客戶')
    partner_name = fields.Char(u'客戶名称')
    account_id = fields.Many2one('account.account', u'科目')
    account_name = fields.Char(u'科目名称')
    account_code = fields.Char(u'科目编码')
    max_date = fields.Datetime(u'修改时间')
    last_time_entries_checked = fields.Date(u'最新发票及付款日期')
    total_debit = fields.Float(string=u'借方总金额', group_operator='sum')
    total_credit = fields.Float(string=u'贷方总金额', group_operator='sum')
    balance = fields.Float(string='差额', group_operator='sum')
    account_type = fields.Char()

    def _select(self, res_type, res_ids=None, account_type=None):
        if res_ids is not None and len(res_ids) == 0:
            # Note : this short-circuiting is better for performances, but also required
            # since postgresql doesn't implement empty list (so 'AND id in ()' is useless)
            return []
        res_ids = res_ids and tuple(res_ids)

        assert res_type in ('partner', 'account')
        is_partner = res_type == 'partner'
        res_alias = is_partner and 'p' or 'a'
        select_str = """
            SELECT partner_id as ID, {0} account_id, account_name, account_code, max_date,
                   to_char(last_time_entries_checked, 'YYYY-MM-DD') AS last_time_entries_checked,
                   total_debit, total_credit,(total_debit-total_credit) balance, account_type
            FROM (
                    SELECT {1}
                        {res_alias}.last_time_entries_checked AS last_time_entries_checked,
                        a.id AS account_id,
                        a.name AS account_name,
                        a.code AS account_code,
                        MAX(l.write_date) AS max_date,
                        SUM (
                            CASE
                            WHEN l.debit > 0 THEN
                                l.amount_residual
                            ELSE
                                0
                            END
                        ) AS total_debit,
                        SUM (
                            CASE
                            WHEN l.credit > 0 THEN
                                ABS (l.amount_residual)
                            ELSE
                                0
                            END
                        ) AS total_credit,
                        at.type as account_type
                    FROM
                        account_move_line l
                        RIGHT JOIN account_account a ON (a.id = l.account_id)
                        RIGHT JOIN account_account_type at ON (at.id = a.user_type_id)
                        {2}
                    WHERE
                        a.reconcile IS TRUE
                        AND l.full_reconcile_id is NULL
                        {3}
                        {4}
                        {5}
                        AND l.company_id = {6}
                        AND EXISTS (
                            SELECT NULL
                            FROM account_move_line l
                            WHERE l.account_id = a.id
                            {7}
                            AND l.amount_residual > 0
                        )
                        AND EXISTS (
                            SELECT NULL
                            FROM account_move_line l
                            WHERE l.account_id = a.id
                            {7}
                            AND l.amount_residual < 0
                        )
                        AND l.reconciled IS FALSE
                    GROUP BY {8} a.id, a.name, a.code, at.type, {res_alias}.last_time_entries_checked
                    ORDER BY {res_alias}.last_time_entries_checked
                ) as s
            WHERE (last_time_entries_checked IS NULL OR max_date > last_time_entries_checked)
        """.format(
                is_partner and 'partner_id, partner_name,' or ' ',
                is_partner and 'p.id AS partner_id, p.name AS partner_name,' or ' ',
                is_partner and 'RIGHT JOIN res_partner p ON (l.partner_id = p.id)' or ' ',
                is_partner and ' ' or "AND at.type <> 'payable' AND at.type <> 'receivable'",
                account_type and "AND at.type in ('payable', 'receivable')" or '',
                res_ids and 'AND ' + res_alias + '.id in %(res_ids)s' or '',
                self.env.user.company_id.id,
                is_partner and 'AND l.partner_id = p.id' or ' ',
                is_partner and 'l.partner_id, p.id,' or ' ',
                res_alias=res_alias
            )
        return select_str

    @api.multi
    def account_charge(self):
        action_context = {'show_mode_selector': True,
                          'mode': self._context.get('mode'),
                          'company_ids': self._context.get('company_ids'),
                          'partner_ids': self.ids}
        return {
            'type': 'ir.actions.client',
            'tag': 'manual_reconciliation_view',
            'context': action_context,
        }

    # @api.multi
    def account_charge_auto(self):
        # 先检查是否既是客户，又是供应商
        # self._check_is_either_customer_and_supplier()

        move_line_obj = self.env['account.move.line']
        for record in self:
            if record.total_debit != record.total_credit:
                raise ValidationError(u'当应付总金额和已付总金额相等时，才能自动核销')
            move_lines = move_line_obj.get_move_lines_for_manual_reconciliation(record.account_id.id,
                                                                                                partner_id=record.partner_id.id)
            data = [{'new_mv_line_dicts': [], 'type': None, 'id': None, 'mv_line_ids': [m_l.get('id') for m_l in move_lines]}]
            move_line_obj.with_context({'is_all_reconcile': True}).process_reconciliations(data)
        return True

    @api.multi
    def account_charge_auto_confirm(self):
        # 客户要求在自动核销时添加一个确认步骤，直接添加confirm属性无效，通过wizard来实现

        # 先检查是否既是客户，又是供应商
        # self._check_is_either_customer_and_supplier()

        res = self.env['account.charge.confirm.wizard'].create({'charge_id': self.id})
        form_view_id = self.env.ref('account_extend.xdl_account_charge_auto_confirm_wizard').id

        action = {
            'type': 'ir.actions.act_window',
            'views': [(form_view_id, 'form')],
            'view_mode': 'tree,form',
            'name': '自动核销',
            'res_model': 'account.charge.confirm.wizard',
            'target': 'new',
            'res_id': res.id,
            # 'context': dict(self.env.context, is_taxed=self.is_taxed, search_default_group_product=True),
            }

        return action
    
    def _check_is_either_customer_and_supplier(self):
        # 先检查是否既是客户，又是供应商
        partners = self.env['res.partner'].sudo().search([('name', '=', self.partner_id.name), ('customer', '=', True)])
        if len(partners) > 0:
            raise ValidationError('供应商 “%s” 同时也是客户，请手动核销！' % self.partner_id.name)
        return

    @api.model_cr
    def init(self):
        res_type, res_ids, account_type = 'partner',  None, ('payable', 'receivable')
        tools.drop_view_if_exists(self.env.cr, self._table)
        self.env.cr.execute("""CREATE or REPLACE VIEW %s as (
            %s
            )""" % (self._table, self._select(res_type, res_ids, account_type)))


class AccountChargeOffWizard(models.TransientModel):
    _name = "account.charge.confirm.wizard"

    charge_id = fields.Many2one('account.charge.off', string="付款匹配单据", required=True)

    @api.multi
    def confirm(self):
        self.ensure_one()
        if self.charge_id:
            self.charge_id.account_charge_auto()



# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
